﻿namespace MvcCss
{
	using System;
	using System.Collections.Generic;
	using System.IO;
	using System.Text;
	using System.Web.Mvc;
	using System.Web.Routing;

	public static class CssExtensions
	{
		private static string _cssFolderUrls = "~/Content,~/Content/Css";
		private static string _siteCssUrl = "Site";
		private static bool _appendTimestamp = false;

		public static string MvcCss(this HtmlHelper htmlHelper)
		{
			return MvcCss(htmlHelper, new RouteValueDictionary());
		}

		public static string MvcCss(this HtmlHelper htmlHelper, object htmlAttributes)
		{
			return MvcCss(htmlHelper, new RouteValueDictionary(htmlAttributes));
		}

		public static string MvcCss(this HtmlHelper htmlHelper, bool appendTimestamp)
		{
			_appendTimestamp = appendTimestamp;
			return MvcCss(htmlHelper);
		}

		public static string MvcCss(this HtmlHelper htmlHelper, bool appendTimestamp, object htmlAttributes)
		{
			_appendTimestamp = appendTimestamp;
			return MvcCss(htmlHelper, htmlAttributes);
		}

		public static string MvcCss(this HtmlHelper htmlHelper, string siteCss)
		{
			_siteCssUrl = siteCss;
			return MvcCss(htmlHelper);
		}

		public static string MvcCss(this HtmlHelper htmlHelper, string siteCss, object htmlAttributes)
		{
			_siteCssUrl = siteCss;
			return MvcCss(htmlHelper, htmlAttributes);
		}

		public static string MvcCss(this HtmlHelper htmlHelper, bool appendTimestamp, string siteCss)
		{
			_appendTimestamp = appendTimestamp;
			_siteCssUrl = siteCss;
			return MvcCss(htmlHelper);
		}

		public static string MvcCss(this HtmlHelper htmlHelper, bool appendTimestamp, string siteCss, object htmlAttributes)
		{
			_appendTimestamp = appendTimestamp;
			_siteCssUrl =  siteCss;
			return MvcCss(htmlHelper, htmlAttributes);
		}

		public static string MvcCss(this HtmlHelper htmlHelper, IDictionary<string, object> htmlAttributes)
		{
			string controller = htmlHelper.ViewContext.RouteData.Values["controller"].ToString();
			string action = htmlHelper.ViewContext.RouteData.Values["action"].ToString();

			StringBuilder stringBuilder = new StringBuilder();

			string siteCssUrl = LocateCss(htmlHelper, _siteCssUrl);
			if (!String.IsNullOrEmpty(siteCssUrl)) stringBuilder.Append(CssHelper(htmlHelper, siteCssUrl, htmlAttributes));

			string controllerCssUrl = LocateCss(htmlHelper, controller);
			if (!String.IsNullOrEmpty(controllerCssUrl)) stringBuilder.Append(CssHelper(htmlHelper, controllerCssUrl, htmlAttributes));

			string actionCssUrl = LocateCss(htmlHelper, controller + "-" + action);
			if (!String.IsNullOrEmpty(actionCssUrl)) stringBuilder.Append(CssHelper(htmlHelper, actionCssUrl, htmlAttributes));
			
			return stringBuilder.ToString();
		}

		private static string LocateCss(this HtmlHelper htmlHelper, string fileName)
		{
			fileName = fileName.EndsWith(".css") ? fileName : fileName + ".css";

			string[] cssFolderUrls = _cssFolderUrls.Split(", ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
			UrlHelper urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
			string minFileName = fileName.EndsWith(".min.css") ? fileName : fileName.Replace(".css", ".min.css");

			foreach (string cssFolderUrl in cssFolderUrls) {
				string cssFolderPath = htmlHelper.ViewContext.HttpContext.Server.MapPath(cssFolderUrl);
				if (Directory.Exists(cssFolderPath)) {
					string cssFilePath = Path.Combine(cssFolderPath, fileName);
					string minFilePath = Path.Combine(cssFolderPath, minFileName);
					if (File.Exists(cssFilePath) || File.Exists(minFilePath)) {
						string fileToUse = cssFilePath;

						if (!htmlHelper.ViewContext.HttpContext.IsDebuggingEnabled) {
							if (File.Exists(minFilePath) && File.Exists(cssFilePath) && File.GetLastWriteTimeUtc(minFilePath) >= File.GetLastWriteTimeUtc(cssFilePath))
								fileToUse = minFilePath;
						}

						if (fileToUse != null) {
							string cssUrl = urlHelper.Content(cssFolderUrl.TrimEnd('/') + "/" + (new FileInfo(fileToUse)).Name);
							if (_appendTimestamp) cssUrl += "?" + TimestampString(fileToUse);
							return cssUrl;
						}
					}
				}
			}
			return null;
		}

		private static string CssHelper(this HtmlHelper htmlHelper, string cssUrl, IDictionary<string, object> htmlAttributes)
		{
			TagBuilder tagBuilder = new TagBuilder("link");
			tagBuilder.MergeAttributes(htmlAttributes);
			tagBuilder.MergeAttribute("rel", "stylesheet");
			tagBuilder.MergeAttribute("type", "text/css");
			tagBuilder.MergeAttribute("href", cssUrl);
			return tagBuilder.ToString(TagRenderMode.SelfClosing);
		}

		static DateTime CenturyBegin = new DateTime(2005, 1, 1);
		private static string TimestampString(string filePath)
		{
			return Convert.ToString((File.GetLastWriteTimeUtc(filePath).Ticks - CenturyBegin.Ticks) / 1000000000, 16);
		}

	}
}
